<template>
  <div class="model-container">
    <div ref="container" class="three-container"></div>
    <div class="chat-container" :class="{ 'chat-open': isChatOpen }">
      <div class="chat-header" @click="toggleChat">
        <span>AI助手</span>
      </div>
      <div class="chat-content">
        <div class="messages">
          <div v-for="(msg, index) in messages" :key="index" :class="msg.type">
            {{ msg.text }}
          </div>
        </div>
        <div class="input-area">
          <input 
            v-model="userInput" 
            @keyup.enter="sendMessage"
            placeholder="输入消息..."
          />
          <button @click="sendMessage">发送</button>
        </div>
      </div>
    </div>
    <div class="window-controls">
      <button @click="minimizeWindow" :title="isMinimized ? '恢复' : '最小化'">
        {{ isMinimized ? '+' : '-' }}
      </button>
      <button @click="closeWindow" title="关闭">×</button>
    </div>
  </div>
</template>

<script>
import * as THREE from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'

export default {
  name: 'ModelViewer',
  data() {
    return {
      scene: null,
      camera: null,
      renderer: null,
      model: null,
      controls: null,
      isMinimized: false,
      isChatOpen: true,
      originalSize: { width: 300, height: 400 },
      pos1: 0,
      pos2: 0,
      pos3: 0,
      pos4: 0,
      userInput: '',
      messages: [
        { 
          type: 'bot', 
          text: '你好！我是你的AI助手，有什么可以帮你的吗？',
          emotion: 'happy'
        }
      ],
      animationState: 'idle', // idle, talking, listening, questioning
      conversationId: '', // 用于保持对话上下文
      isLoading: false,
      isListening: false, // 语音识别状态
      isSpeaking: false, // 语音合成状态
      recognition: null, // 语音识别实例
      synth: window.speechSynthesis, // 语音合成
      voices: [], // 可用语音列表
      selectedVoice: null, // 选择的语音
      faceBones: null, // 面部骨骼
      lipSyncParams: { // 嘴唇同步参数
        mouthOpen: 0,
        mouthShape: 'A',
        visemes: {
          A: 0, E: 0, I: 0, O: 0, U: 0
        }
      },
      lipSyncInterval: null, // 嘴唇同步定时器
      userProfile: { // 用户档案
        name: '访客',
        preferences: {},
        conversationHistory: []
      },
      emotionState: 'neutral', // neutral, happy, sad, angry, surprised
      personalityTraits: { // 数字人个性
        friendliness: 0.8,
        professionalism: 0.7,
        humor: 0.5
      },
    }
    },
    mounted() {
    this.initThree()
    this.loadModel()
    this.animate()
    this.setupDrag()
    this.initSpeech()
  },
  methods: {
    toggleChat() {
      this.isChatOpen = !this.isChatOpen
    },
    async sendMessage() {
      if (!this.userInput.trim()) return
      
      // 添加用户消息
      const userMessage = this.userInput
      this.messages.push({ 
        type: 'user', 
        text: userMessage,
        timestamp: new Date().toISOString()
      })
      this.userInput = ''
      
      // 分析用户情绪
      this.analyzeUserEmotion(userMessage)
      
      // 触发模型动画
      this.triggerTalkingAnimation()
      
      try {
        // 调用增强版AI API
        const response = await this.$http.post('/ai/chat-enhanced', {
          message: userMessage,
          conversation_id: this.conversationId || '',
          user_profile: this.userProfile,
          emotion_state: this.emotionState,
          personality_traits: this.personalityTraits
        })
        
        // 处理API响应
        if (response.data && response.data.code === 200) {
          const { 
            reply, 
            conversation_id, 
            emotion, 
            should_remember,
            memory_key 
          } = response.data
          
          // 更新对话
          this.messages.push({ 
            type: 'bot', 
            text: reply,
            emotion: emotion || 'neutral'
          })
          this.conversationId = conversation_id || ''
          
          // 更新用户档案
          if (should_remember && memory_key) {
            this.userProfile.preferences[memory_key] = reply
          }
          
          // 更新对话历史
          this.userProfile.conversationHistory.push({
            user: userMessage,
            bot: reply,
            timestamp: new Date().toISOString()
          })
          
          // 语音播报回复
          this.speak(reply)
          
          // 根据情绪更新动画
          this.updateEmotionAnimation(emotion)
        } else {
          throw new Error(response.data?.msg || 'API请求失败')
        }
      } catch (error) {
        this.$message.error('调用AI API出错')
      }
    },
    triggerTalkingAnimation() {
      // 说话动画
      this.animationState = 'talking'
      if (this.model) {
        // 添加头部轻微上下移动
        if (!this.headBobAction) {
          const clip = new THREE.AnimationClip('head_bob', -1, [
            new THREE.VectorKeyframeTrack(
              '.bones[face_head].position[y]',
              [0, 0.5, 1.0],
              [0, 0.03, 0]
            )
          ])
          this.headBobAction = this.mixer.clipAction(clip)
          this.headBobAction.setLoop(THREE.LoopRepeat)
        }
        this.headBobAction.play()
      }
    },
    triggerListeningAnimation() {
      // 聆听动画
      this.animationState = 'listening'
      if (this.model) {
        // 添加点头动作
        if (!this.nodAction) {
          const clip = new THREE.AnimationClip('head_nod', 1.5, [
            new THREE.VectorKeyframeTrack(
              '.bones[face_head].rotation[x]',
              [0, 0.5, 1.0, 1.5],
              [0, 0.2, 0, -0.1]
            )
          ])
          this.nodAction = this.mixer.clipAction(clip)
        }
        this.nodAction.reset().play()
        
        // 添加眨眼动作
        if (!this.blinkAction) {
          const clip = new THREE.AnimationClip('eye_blink', 0.5, [
            new THREE.NumberKeyframeTrack(
              '.bones[face_eyelid].scale[y]',
              [0, 0.2, 0.4, 0.5],
              [1, 0.1, 0.1, 1]
            )
          ])
          this.blinkAction = this.mixer.clipAction(clip)
        }
        this.blinkAction.reset().play()
      }
      setTimeout(() => {
        this.animationState = 'idle'
      }, 2000)
    },
    
    triggerQuestionAnimation() {
      // 提问动画
      this.animationState = 'questioning'
      if (this.model) {
        // 这里可以添加模型歪头等动作
      }
      setTimeout(() => {
        this.animationState = 'idle'
      }, 2500)
    },
    
    initSpeech() {
      // 初始化语音识别
      if ('webkitSpeechRecognition' in window) {
        this.recognition = new webkitSpeechRecognition()
        this.recognition.continuous = false
        this.recognition.interimResults = false
        this.recognition.lang = 'zh-CN'
        
        this.recognition.onstart = () => {
          this.isListening = true
          this.triggerListeningAnimation()
        }
        
        this.recognition.onresult = (event) => {
          const transcript = event.results[0][0].transcript
          this.userInput = transcript
          this.sendMessage()
        }
        
        this.recognition.onerror = (event) => {
          this.$message.error('语音识别错误')
          this.isListening = false
        }
        
        this.recognition.onend = () => {
          this.isListening = false
        }
      }
      
      // 加载语音合成声音
      this.synth.onvoiceschanged = () => {
        this.voices = this.synth.getVoices().filter(v => v.lang.includes('zh'))
        this.selectedVoice = this.voices.find(v => v.name.includes('Chinese')) || this.voices[0]
      }
    },
    
    startListening() {
      if (this.recognition && !this.isListening) {
        this.recognition.start()
      }
    },
    
    findFaceBones(model) {
      // 查找面部骨骼
      model.traverse((child) => {
        if (child.isBone && child.name.toLowerCase().includes('face')) {
          this.faceBones = this.faceBones || {}
          this.faceBones[child.name] = child
        }
      })
    },
    
    updateLipSync(visemes) {
      // 更新嘴唇同步参数
      if (!this.faceBones) return
      
      // 根据音素更新面部骨骼
      Object.keys(visemes).forEach(viseme => {
        const value = visemes[viseme]
        const boneName = `face_jaw_${viseme.toLowerCase()}`
        if (this.faceBones[boneName]) {
          // 根据情绪调整嘴部动作幅度
          const emotionFactor = this.getEmotionFactor()
          this.faceBones[boneName].rotation.x = value * 0.1 * emotionFactor
        }
      })
      
      // 更新嘴巴张开程度
      this.lipSyncParams.mouthOpen = Math.max(
        visemes.A, visemes.E, visemes.I, visemes.O, visemes.U
      )
    },
    
    analyzeUserEmotion(text) {
      // 简单情绪分析
      const positiveWords = ['开心', '高兴', '喜欢', '爱', '棒']
      const negativeWords = ['生气', '讨厌', '恨', '糟糕', '差']
      
      if (positiveWords.some(word => text.includes(word))) {
        this.emotionState = 'happy'
      } else if (negativeWords.some(word => text.includes(word))) {
        this.emotionState = 'angry'
      } else {
        this.emotionState = 'neutral'
      }
    },
    
    updateEmotionAnimation(emotion) {
      // 根据情绪更新动画状态
      this.emotionState = emotion || 'neutral'
      
      switch (this.emotionState) {
        case 'happy':
          this.animationState = 'happy'
          break
        case 'sad':
          this.animationState = 'sad'
          break
        case 'angry':
          this.animationState = 'angry'
          break
        case 'surprised':
          this.animationState = 'surprised'
          break
        default:
          if (this.messages[this.messages.length - 1].text.includes('?')) {
            this.animationState = 'questioning'
          } else {
            this.animationState = 'listening'
          }
      }
    },
    
    getEmotionFactor() {
      // 获取情绪影响系数
      switch (this.emotionState) {
        case 'happy': return 1.2
        case 'angry': return 1.3
        case 'sad': return 0.8
        case 'surprised': return 1.5
        default: return 1.0
      }
    },
    
    speak(text) {
      if (this.synth.speaking) {
        this.synth.cancel()
      }
      
      const utterance = new SpeechSynthesisUtterance(text)
      utterance.voice = this.selectedVoice
      utterance.rate = 0.9
      utterance.pitch = 1.0
      
      // 语音分析间隔
      const analysisInterval = 50 // ms
      let lastAnalysisTime = 0
      
      utterance.onstart = () => {
        this.triggerTalkingAnimation()
        this.isSpeaking = true
        
        // 开始嘴唇同步分析
        this.lipSyncInterval = setInterval(() => {
          const currentTime = this.synth.currentTime || 0
          if (currentTime > lastAnalysisTime) {
            // 模拟根据语音生成音素参数
            const visemes = {
              A: Math.random() * 0.5 + 0.5,
              E: Math.random() * 0.3 + 0.2,
              I: Math.random() * 0.4 + 0.1,
              O: Math.random() * 0.6 + 0.3,
              U: Math.random() * 0.2 + 0.1
            }
            this.updateLipSync(visemes)
            lastAnalysisTime = currentTime
          }
        }, analysisInterval)
      }
      
      utterance.onend = () => {
        this.animationState = 'idle'
        this.isSpeaking = false
        clearInterval(this.lipSyncInterval)
        
        // 重置面部表情
        if (this.faceBones) {
          Object.values(this.faceBones).forEach(bone => {
            bone.rotation.x = 0
          })
        }
      }
      
      this.synth.speak(utterance)
    },
    setupDrag() {
      const container = this.$refs.container.parentElement
      this.pos1 = 0
      this.pos2 = 0
      this.pos3 = 0
      this.pos4 = 0
      
      container.onmousedown = (e) => {
        if (e.target !== container && !e.target.classList.contains('window-controls')) {
          return
        }
        
        e = e || window.event
        e.preventDefault()
        this.pos3 = e.clientX
        this.pos4 = e.clientY
        document.onmouseup = this.closeDragElement
        document.onmousemove = this.elementDrag
      }
    },
    
    elementDrag(e) {
      e = e || window.event
      e.preventDefault()
      const container = this.$refs.container.parentElement
      this.pos1 = this.pos3 - e.clientX
      this.pos2 = this.pos4 - e.clientY
      this.pos3 = e.clientX
      this.pos4 = e.clientY
      container.style.top = (container.offsetTop - this.pos2) + "px"
      container.style.left = (container.offsetLeft - this.pos1) + "px"
    },
    
    closeDragElement() {
      document.onmouseup = null
      document.onmousemove = null
    },
    
    minimizeWindow() {
      const container = this.$refs.container.parentElement
      this.isMinimized = !this.isMinimized
      
      if (this.isMinimized) {
        this.originalSize = {
          width: container.clientWidth,
          height: container.clientHeight
        }
        container.style.width = '80px'
        container.style.height = '80px'
        container.style.overflow = 'hidden'
      } else {
        container.style.width = `${this.originalSize.width}px`
        container.style.height = `${this.originalSize.height}px`
        container.style.overflow = 'hidden'
        this.onWindowResize()
      }
    },
    
    closeWindow() {
      const container = this.$refs.container.parentElement
      container.style.display = 'none'
      // 释放资源
      if (this.renderer) {
        this.renderer.dispose()
      }
      if (this.model) {
        this.scene.remove(this.model)
      }
    },
    initThree() {
      // 创建场景
      this.scene = new THREE.Scene()
      
      // 创建相机 - 针对小窗口优化
      this.camera = new THREE.PerspectiveCamera(
        60, // 增大视野角度，拉大视角
        300 / 400, // 固定为悬浮窗初始宽高比
        0.1,
        1000
      )
      this.camera.position.set(0, 1.5, 4) // 调整相机位置更远更高

      // 创建渲染器并优化小窗口显示
      this.renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true,
        powerPreference: "high-performance" // 性能优化
      })
      this.renderer.setSize(300, 400) // 固定为悬浮窗初始大小
      this.renderer.setClearColor(0x000000, 0) // 完全透明背景
      this.renderer.shadowMap.enabled = false // 禁用阴影
      this.renderer.setPixelRatio(window.devicePixelRatio) // 适配高清屏
      this.$refs.container.appendChild(this.renderer.domElement)

      // 添加轨道控制器
      this.controls = new OrbitControls(this.camera, this.renderer.domElement)
      this.controls.enableDamping = true
      this.controls.dampingFactor = 0.25
      
      // 限制交互区域为模型容器
      const container = this.$refs.container
      this.controls.domElement = container
      container.appendChild(this.renderer.domElement)

      // 优化光照设置 - 针对小窗口调整
      const ambientLight = new THREE.AmbientLight(0xffffff, 0.8) // 降低环境光强度
      this.scene.add(ambientLight)

      // 主光源 - 更集中
      const mainLight = new THREE.DirectionalLight(0xffffff, 1.2)
      mainLight.position.set(0.3, 0.8, 0.5)
      mainLight.castShadow = false // 确保不产生阴影
      ambientLight.intensity = 0.5
      mainLight.intensity = 0.8
      this.scene.add(mainLight)

      // 简化补光系统
      const fillLight = new THREE.DirectionalLight(0xffffff, 0.6)
      fillLight.position.set(-0.3, 0.5, -0.3)
      fillLight.intensity = 0.4
      this.scene.add(fillLight)

      // 窗口大小调整事件
      window.addEventListener('resize', this.onWindowResize)
    },
    loadModel() {
      // 先清理现有资源
      if (this.model) {
        this.scene.remove(this.model)
        this.model = null
      }
      if (this.mixer) {
        this.mixer.stopAllAction()
        this.mixer = null
      }

      const loader = new GLTFLoader()
      loader.load(
        process.env.BASE_URL + 'models/lady_in_black_dress.glb',
        (gltf) => {
          try {
            this.model = gltf.scene
            this.scene.add(this.model)
            
            // 旋转模型使其面向用户
            this.model.rotation.y = Math.PI
            
            // 自动调整模型大小和位置
            const box = new THREE.Box3().setFromObject(this.model)
            const center = box.getCenter(new THREE.Vector3())
            const size = box.getSize(new THREE.Vector3())
            
            this.model.position.x += (this.model.position.x - center.x)
            this.model.position.y += (this.model.position.y - center.y)
            this.model.position.z += (this.model.position.z - center.z)
            
            // 调整相机位置
            this.camera.position.z = size.length() * 0.8
            this.controls.update()

            // 初始化动画混合器
            this.mixer = new THREE.AnimationMixer(this.model)
            this.clock = new THREE.Clock()
            this.actions = []
            
            // 查找面部骨骼用于表情控制
            this.findFaceBones(this.model)
            
            // 初始化嘴唇同步参数
            this.lipSyncParams = {
              mouthOpen: 0,
              mouthShape: 'A',
              visemes: {
                A: 0, E: 0, I: 0, O: 0, U: 0
              }
            }
            
            // 播放所有可用动画
            if (gltf.animations?.length) {
              gltf.animations.forEach((clip) => {
                try {
                  const action = this.mixer.clipAction(clip)
                  action.setLoop(THREE.LoopRepeat, Infinity)
                  action.play()
                  this.actions.push(action)
                } catch (e) {
                  this.$message.error('无法播放动画')
                }
              })
            }
          } catch (e) {
            this.$message.error('处理模型时出错')
          }
        },
        (xhr) => {
          // 模型加载进度
        },
        (error) => {
          this.$message.error('加载模型出错')
        }
      )
    },
    animate() {
      // 使用固定时间步长更新动画
      const targetFPS = 30
      const targetDelta = 1 / targetFPS
      let lastTime = 0
      let accumulator = 0
      
      const animateLoop = (time) => {
        requestAnimationFrame(animateLoop)
        
        // 计算时间增量
        const deltaTime = Math.min((time - lastTime) / 1000, 0.1) // 限制最大delta时间
        lastTime = time
        accumulator += deltaTime
        
        // 只在窗口可见时更新
        if (document.hidden) return
        
        // 固定时间步长更新
        while (accumulator >= targetDelta) {
          this.update(targetDelta)
          accumulator -= targetDelta
        }
        
        // 渲染场景
        this.renderer.render(this.scene, this.camera)
      }
      
      animateLoop(0)
    },
    
    update(deltaTime) {
      // 更新控制器
      this.controls.update()
      
      // 更新动画混合器
      if (this.mixer) {
        this.mixer.update(deltaTime)
      }
      
      // 更新嘴唇同步
      if (this.isSpeaking && this.faceBones) {
        // 根据当前语音状态更新面部骨骼
        Object.keys(this.lipSyncParams.visemes).forEach(viseme => {
          const boneName = `face_jaw_${viseme.toLowerCase()}`
          if (this.faceBones[boneName]) {
            // 平滑过渡到目标值
            this.faceBones[boneName].rotation.x = 
              THREE.MathUtils.lerp(
                this.faceBones[boneName].rotation.x,
                this.lipSyncParams.visemes[viseme] * 0.1,
                0.2
              )
          }
        })
      }
    },
    onWindowResize() {
      const container = this.$refs.container
      const width = container.clientWidth
      const height = container.clientHeight
      this.camera.aspect = width / height
      this.camera.updateProjectionMatrix()
      this.renderer.setSize(width, height)
    },
    beforeDestroy() {
      window.removeEventListener('resize', this.onWindowResize)
      if (this.$refs.container && this.renderer.domElement) {
        this.$refs.container.removeChild(this.renderer.domElement)
      }
    }
  }
}
</script>

<style scoped>
.model-container {
  display: flex;
  flex-direction: column;
  position: fixed;
  right: 20px;
  bottom: 20px;
  width: 300px;
  height: 400px;
  z-index: 999;
  background: transparent;
  border-radius: 10px;
  overflow: hidden;
  resize: both;
  min-width: 200px;
  min-height: 300px;
  cursor: move;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.three-container {
  width: 100%;
  height: 70%;
}

.chat-container {
  height: 30%;
  background: rgba(255, 255, 255, 0.9);
  border-top: 1px solid #eee;
  transition: all 0.3s ease;
  overflow: hidden;
}

.chat-container.chat-open {
  height: 30%;
}

.chat-header {
  padding: 8px 12px;
  background: #3a86ff;
  color: white;
  cursor: pointer;
  font-size: 14px;
}

.chat-content {
  display: flex;
  flex-direction: column;
  height: calc(100% - 36px);
}

.messages {
  flex: 1;
  padding: 8px;
  overflow-y: auto;
}

.messages .user {
  text-align: right;
  margin: 4px 0;
  padding: 6px 10px;
  background: #e3f2fd;
  border-radius: 10px 10px 0 10px;
  display: inline-block;
}

.messages .bot {
  text-align: left;
  margin: 4px 0;
  padding: 6px 10px;
  background: #f5f5f5;
  border-radius: 10px 10px 10px 0;
  display: inline-block;
  position: relative;
}

.messages .bot.happy {
  background: #e3f7e8;
  border-left: 3px solid #4caf50;
}

.messages .bot.sad {
  background: #f0f5ff;
  border-left: 3px solid #2196f3;
}

.messages .bot.angry {
  background: #ffebee;
  border-left: 3px solid #f44336;
}

.messages .bot.surprised {
  background: #fff8e1;
  border-left: 3px solid #ffc107;
}

.input-area {
  display: flex;
  padding: 8px;
  border-top: 1px solid #eee;
  align-items: center;
}

.input-area input {
  flex: 1;
  padding: 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
}

.mic-icon {
  margin-left: 8px;
  cursor: pointer;
  color: #ff4757;
  font-size: 20px;
}

.input-area button {
  padding: 8px 16px;
  background: #3a86ff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  margin-left: 8px;
}

.input-area button.voice-btn {
  background: #ff4757;
}

.input-area button.voice-btn.listening {
  animation: pulse 1.5s infinite;
}

@keyframes pulse {
  0% {
    box-shadow: 0 0 0 0 rgba(255, 71, 87, 0.7);
  }
  70% {
    box-shadow: 0 0 0 10px rgba(255, 71, 87, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(255, 71, 87, 0);
  }
}

/* 添加悬浮窗控制按钮 */
.window-controls {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 1000;
  display: flex;
  gap: 8px;
}

.window-controls button {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  border: none;
  background: rgba(0, 0, 0, 0.2);
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.2s;
  font-size: 16px;
  font-weight: bold;
  outline: none;
}

.window-controls button:hover {
  background: rgba(0, 0, 0, 0.4);
  transform: scale(1.1);
}

.window-controls button:hover {
  background: rgba(0, 0, 0, 0.4);
}
</style>